package com.suncreate.radarscan.service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;
import org.elasticsearch.search.aggregations.metrics.avg.Avg;
import org.elasticsearch.search.aggregations.metrics.avg.AvgAggregationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.suncreate.radarscan.dao.RadarInfoEntityMapper;
import com.suncreate.radarscan.dao.RadarLaneEntityMapper;
import com.suncreate.radarscan.dao.StatisticEntityMapper;
import com.suncreate.radarscan.entity.RadarInfoEntity;
import com.suncreate.radarscan.entity.StatisticEntity;
import com.suncreate.util.ESUtils;

@Service
public class RadarStatisticService {
	//日志记录        
    private Logger logger = LoggerFactory.getLogger(RadarStatisticService.class);
	@Autowired
	private RadarInfoEntityMapper radarInfoDao;
	
	@Autowired
	private StatisticEntityMapper statisticDao;
	
	@Autowired
	private RadarLaneEntityMapper radarLaneDao;
	
	private static Timer statisTimer = new Timer("statisTimer");//以非守护方式启动统计分析定时器
	
	private static StatisticTask statisTask;
	/*
	 * 启动统计分析定时器
	 */
	public void startStatistic() {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); 
			Date forwardDate = sdf.parse("1988-06-14 08:16:16");//设置一个很早的时间点，让定时器立马执行
			statisTask = new StatisticTask(radarInfoDao,statisticDao,radarLaneDao,getTimeNow());
//			statisTask = new StatisticTask(radarInfoDao,statisticDao,1505264400000l);
			
			//执行频率为每5分钟执行一次
			statisTimer.schedule(statisTask,forwardDate,5*60*1000);
		} catch (ParseException ex) {
			logger.debug("",ex);
		}
	}
	
	/**
	 * 将当前时间戳转化为规格化的时间戳：去掉毫秒数、分钟数为5的倍数
	 * 例如：输入的时间戳为：2017-09-15 19:43:38 则输出为：2017-09-15 19:40:00
	 */
	public long getTimeNow() {
		try {
			long nowTime = new Date().getTime();
			//去掉毫秒数
			SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:00" ); 
			String nowTimeString = sdf.format(nowTime);
			Date date = sdf.parse(nowTimeString);
			
			//将分钟数设为5的整数倍
			int minutes = date.getMinutes();
			int minuteNum = minutes/5;
			date.setMinutes(minuteNum*5);
			return date.getTime();
		} catch (ParseException ex) {
			logger.error("",ex);
			return -1;
		}
	}
}

class StatisticTask extends TimerTask{
	//日志记录        
    private Logger logger = LoggerFactory.getLogger(StatisticTask.class);
    
	private static long startTime;
	
	private RadarInfoEntityMapper radarInfoDao;
	
	private StatisticEntityMapper statisticDao;
	
	private RadarLaneEntityMapper radarLaneDao;
	
	@Override
	public void run() {
			try {
				logger.debug("统计事件分析开始，开始时间为："+ StatisticTask.startTime);
				List<Bucket> statisList = getStatisticData(StatisticTask.startTime);
				if(statisList.isEmpty()) {
					logger.debug("ES中数据为空，查询开始时间为:" + StatisticTask.startTime);
					StatisticTask.startTime += 5*60*1000;
					return;
				}
				for(Bucket buck:statisList) {
					String radarNo = buck.getKeyAsString().toUpperCase();
					long dataCounts = buck.getDocCount();
					Avg aggSpeed = buck.getAggregations().get("avgSpeed");
					double avgSpeed = aggSpeed.getValue();
					
					long avgTraffic = getAvgTraffic(dataCounts,avgSpeed);
					
					int radarId = queryRadarId(radarNo);
					if(-1 != radarId) {
						StatisticEntity statisEntity = new StatisticEntity();
						statisEntity.setRadarId(radarId);
						statisEntity.setStatisticAvgSpeed(new BigDecimal(avgSpeed));
						statisEntity.setStatisticTraffic(new Long(avgTraffic).intValue());
						statisEntity.setStatisticStartTime(StatisticTask.startTime - 5*60*1000);
						statisEntity.setStatisticEndTime(StatisticTask.startTime);
						statisEntity.setStatisticJamIndex(getCongestionLevel(radarId,avgSpeed));
						
						statisticDao.insert(statisEntity);
						
						logger.debug("插入统计数据成功，插入的数据为：" + statisEntity.toString());
					}
					
				}
				
				StatisticTask.startTime += 5*60*1000;
			} catch (Exception ex) {
				logger.debug("统计事件时出现异常！异常信息如下：");
				logger.debug("",ex);
				StatisticTask.startTime += 5*60*1000;
			}
	}
	
	/**
	 * 根据道路限速和道路当前平均速度计算道路拥堵等级。
	 * @param maxSpeedLimit 道路最大限速
	 * @param avgSpeed 当前时间平均速度
	 * @return 拥堵级别 1:畅通 2:基本畅通 3:轻度拥堵 4:中度拥堵 5:严重拥堵
	 */
	public int getCongestionLevel(int radarId,double avgSpeed) {
		double maxSpeedLimit = radarLaneDao.getMaxSpeedLimit(radarId);
		if(maxSpeedLimit >= 80) {    //快速路
			if(avgSpeed>65) {        //平均速度>65认为是畅通
				return 1;
			}else if(avgSpeed > 50) {//平均速度介于(50,65],认为是基本畅通
				return 2;
			}else if(avgSpeed > 35) {//平均速度介于(35,50],认为是轻度拥堵
				return 3;
			}else if(avgSpeed >20) { //平均速度介于(20,35],认为是中度拥堵
				return 4;
			}else {                  //平均速度介于(0,20],认为是重度拥堵
				return 5;
			}

		}else if(maxSpeedLimit >=60) {//主干道
			if(avgSpeed>40) {        //平均速度>40认为是畅通
				return 1;
			}else if(avgSpeed > 30) {//平均速度介于(30,40],认为是基本畅通
				return 2;
			}else if(avgSpeed > 20) {//平均速度介于(20,30],认为是轻度拥堵
				return 3;
			}else if(avgSpeed >15) { //平均速度介于(15,20],认为是中度拥堵
				return 4;
			}else {                  //平均速度介于(0,15],认为是重度拥堵
				return 5;
			}

		}else if(maxSpeedLimit >=40) {//次干道
			if(avgSpeed>35) {         //平均速度>35认为是畅通
				return 1;
			}else if(avgSpeed > 25) { //平均速度介于(25,35],认为是基本畅通
				return 2;
			}else if(avgSpeed > 15) { //平均速度介于(15,25],认为是轻度拥堵
				return 3;
			}else if(avgSpeed >10) {  //平均速度介于(10,15],认为是中度拥堵
				return 4;
			}else {                   //平均速度介于(0,10],认为是重度拥堵
				return 5;
			}
		}else {
			logger.info("道路限速太低，无法完成判断");
			return 0;
		}
	}
	
	//通过radarNo查询radarId
	public int queryRadarId(String radarNo) {
		RadarInfoEntity radarInfo = radarInfoDao.selectByRadarNo(radarNo);
		if(null == radarInfo) {
			logger.debug("雷达info表中,没有radarNo为：" + radarNo+"的数据！");
			return -1;
		}
		return radarInfo.getId();
	}
	
	/*
	 * 从ES中读取统计数据
	 * 1.数据范围：当前时刻（精确到分钟）往前5分钟内的所有数据
	 * 2.平均值：ySpeed的平均值
	 */
	public List<Bucket> getStatisticData(long startTime) {
		Client client = ESUtils.getTransportClient();
		logger.debug("getStatisticData函数接受到到startTime:" + startTime);
		QueryBuilder qbByTime = QueryBuilders
				.rangeQuery("time")
				.gte(startTime - 5*60*1000)
				.lte(startTime);
		AvgAggregationBuilder avgAggByYSpeed =
		        AggregationBuilders
		                .avg("avgSpeed")
		                .field("ySpeed");
		AggregationBuilder aggGlobal =  AggregationBuilders.terms("termByRadarNo").field("radarNo").subAggregation(avgAggByYSpeed);
		
		
		SearchResponse queryResponse = client.prepareSearch("radarinfo")  
				.setTypes("radardata")
				.setQuery(qbByTime)
				.addAggregation(aggGlobal)
		        .setFrom(0).setSize(60).setExplain(true)     
		        .execute()     
		        .actionGet();  
		
		Terms aggTerms = queryResponse.getAggregations().get("termByRadarNo");
		client.close();
		return aggTerms.getBuckets();
	}
	
	/*
	 * 计算5分钟内平均车流量
	 * 1.先计算5分钟内平均速度（avgSpeed)
	 * 2.一个目标从检测区经过的平均时间(avgTime)=检测距离(Distance)/平均速度(avgSpeed)
	 * 3.一个目标在平均时间段内共产生消息量avgNum=20*avgTime
	 * 4.平均车流量=总的消息数/avgNum
	 */
	public long getAvgTraffic(long dataCounts,double avgSpeed) {
		
		double distance = 64.854d;//雷达检测距离(单位:m)，现在先写死，以后看能否从数据库中读
		//avgSpeed平均速度：单位(km/h),
//		double avgTime = distance*3600/avgSpeed;//一个目标平均通过时间（单位：毫秒）
//		//雷达采集频率为一秒钟20次，每50毫秒采集一次
//		
////		double traffic = avgTime/50;
//		double traffic = distance*72/avgSpeed;
		
		return (long)Math.ceil(dataCounts*avgSpeed/(distance*72));
	}
	
	public StatisticTask(RadarInfoEntityMapper radarInfoDao,StatisticEntityMapper statisticDao,RadarLaneEntityMapper radarLaneDao,long time) {
		this.radarInfoDao = radarInfoDao;
		this.statisticDao = statisticDao;
		this.radarLaneDao = radarLaneDao;
		StatisticTask.startTime = time;
	}
	
}
